/**
 * Copyright (C) 2010, 2011 Neofonie GmbH
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package eu.dicodeproject.analysis.restapi.controllers;

import eu.dicodeproject.analysis.restapi.ControllerUtils;
import twitter4j.internal.org.json.JSONException;
import twitter4j.internal.org.json.JSONObject;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;

import javax.servlet.http.HttpServletResponse;

import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @author jakob
 */
public class CreationDatesController extends ControllerBase {

  /**
   * Takes a date type as parameter.
   * Returns a JSON that consists of {"result": MAP}, with MAP containing dates
   * (years, months and days) with their frequencies with respect to Tweet creation dates.
   * @param dateType one of {"year", "yearMonth", "yearMonthDay", "hour"}
   *
   * Returns a JSON that consists of {"categoriesLabel": String, "categories": Array, "chartData": Map},
   * with Map containing "creationDates" as key and a map with (date, frequency) as value.
   * Array contains all date values in the required range, and categoriesLabel is the label for these values e.g.
   * {
   *   "categoriesLabel": "yearMonth",
   *   "categories": ["2011-01", "2011-02"],
   *   "chartData": {
   *     "creationDates": {
   *       "2011-01": 54,
   *       "2011-02": 21
   *     }
   *   }
   * }
   * @param source source table (e.g. twitter or blogs)
   * @param callback arbitrary callback parameter
   * @param start earliest date in the result
   * @param stop EXCLUSIVE latest date in the result
   * @param addZeros flag to specify if missing values should be represented by zero entries
   * @param response to write the answer to
   * @throws java.io.IOException inherited from HBase Scan and HttpServletResponse.write
   * @throws twitter4j.internal.org.json.JSONException inherited from JSONObject constructor
   */
  @RequestMapping(value = "{source}/creationDates/{dateType}", method = RequestMethod.GET)
  public void creationDates(@PathVariable String source,
      @PathVariable String dateType, @RequestParam(required = false) String callback,
      @RequestParam(required = false) String start, @RequestParam(required = false) String stop,
      @RequestParam(required = false, defaultValue = "false") boolean addZeros,
      HttpServletResponse response) throws IOException, JSONException {

    // parameters
    String tableName = getTableName(source);
    byte[] columnQualifier = Bytes.toBytes(dateType);  // the dateType is the contentColumn qualifier (e.g. yearMonth or yearMonthDay)

    // collect parameters for result
    JSONObject params = new JSONObject();
    params.put("dateType", dateType);
    params.put("addZeors", addZeros);

    // set HBase Scan
    HTableInterface hTable = getHTable(tableName);
    Scan scan = new Scan();
    scan.addColumn(this.columnFamily, columnQualifier);

    if (start != null) {
      scan.setStartRow(Bytes.toBytes(start));
      params.put("start", start);
    }
    if (stop != null) {
      scan.setStopRow(Bytes.toBytes(stop));
      params.put("stop", stop);
    }

    // read results from scan into a map
    SortedMap<String,Integer> dateMap = new TreeMap<String,Integer>();
    int totalResults = 0;
    for (Result result : hTable.getScanner(scan)) {
      String date = Bytes.toString(result.getRow());
      int count = Integer.valueOf(Bytes.toString(result.getValue(this.columnFamily, columnQualifier)));
      dateMap.put(date, count);
      totalResults++;
    }
    params.put("results", totalResults);

    // get all dates in the required range
    if (start == null) {
      start = dateMap.firstKey();
    }
    SortedSet<String> categories = ControllerUtils.getAllDates(dateType, start, stop);

    // add zeros if required
    if (addZeros) {
      ControllerUtils.addZeros(categories, dateMap);
    }

    // put map into a JSON
    JSONObject json = new JSONObject();
    json.put("parameters", params);
    json.put("categoriesLabel", dateType);
    json.put("categories", categories);
    Map<String,Map<String,Integer>> chartData = new HashMap<String,Map<String,Integer>>();
    chartData.put("creationDates", dateMap);
    json.put("chartData", chartData);

    // write out the result JSON
    respond(callback, json, response);
  }

}
